package org.commons.database.jconnectionpool;

/**
 * Gestisce lo stato attivo o disattivo 
 * di un oggetto per un periodo di tempo. 
 *  
 * @author			Massimo Di Folco
 * @version			<i>1.0 Copyright &#169; 2004 TRS SpA. Created on 7-ott-2003</i>
 */
public class BooleanLock extends Object {
	private boolean value;

	/**
	 * Costruttore con un variabile di input.
	 * @param value che imposta un valore <i>boolean</i>.
	 */
	public BooleanLock(boolean value) {
		this.value = value;
	}

	/**
	 * Costruttore semplice.
	 */
	public BooleanLock() {
		this(false);
	}

	/**
	 * Metodo <i>synchronized</i> che reimposta lo stato di questo oggetto.
	 * @param newValue numero intero.
	 */
	public synchronized void setValue(boolean newValue) {
		if ( newValue != value ) {
			value = newValue;
			notifyAll();
		}
	} // end setValue()

	/**
	 * Restituisce lo stato effettivo <i>(value)</i> di questo oggetto.
	 * @return lo stato di questo oggetto
	 */
	public synchronized boolean isTrue() {
		return value;
	} // end isTrue()

	/**
	 * Restituisce lo stato invertito di questo oggetto.
	 * @return lo stato di questo oggetto
	 */
	public synchronized boolean isFalse() {
		return !value;
	} // end isFalse()

	/**
	 * Per un tempo di <i>msTimeout</i> lo stato dell'oggetto 
	 * rimane quello iniziale (true).
	 *  
	 * @param msTimeout il periodo.
	 * @return un boolean.
	 * @throws InterruptedException Getta un'eccezione adatta al risultato descritto da questo oggetto.
	 */
	public synchronized boolean waitToSetTrue(long msTimeout) throws InterruptedException {
		boolean success = waitUntilFalse(msTimeout);
		if ( success ) {
			setValue(true);
		}
		return success;
	} // end waitToSetTrue()

	/**
	 * Per un tempo di <i>msTimeout</i> lo stato dell'oggetto 
	 * rimane quello iniziale (false).
	 *  
	 * @param msTimeout il periodo.
	 * @return un boolean.
	 * @throws InterruptedException Getta un'eccezione adatta al risultato descritto da questo oggetto.
	 */
	public synchronized boolean waitToSetFalse(long msTimeout) throws InterruptedException {
		boolean success = waitUntilTrue(msTimeout);
		if ( success ) {
			setValue(false);
		}
		return success;
	} // end waitToSetFalse()

	/**
	 * Attende per il tempo di <i>msTimeout</i> se lo stato iniziale 
	 * dell'oggetto e' <i>uguale a <b>True</b></i>.
	 * L'esito � False altrimenti True.
	 *  
	 * @param msTimeout il periodo.
	 * @return un boolean.
	 * @throws InterruptedException Getta un'eccezione adatta al risultato descritto da questo oggetto.
	 */
	public synchronized boolean waitWhileTrue(long msTimeout) throws InterruptedException {
		return waitWhileStateIs(true, msTimeout);
	} // end waitWhileTrue()

	/**
	 * Attende per il tempo di <i>msTimeout</i> se lo stato iniziale 
	 * dell'oggetto e' <i>uguale a <b>False</b></i>.
	 * L'esito � False altrimenti True.
	 *  
	 * @param msTimeout il periodo.
	 * @return un boolean.
	 * @throws InterruptedException Getta un'eccezione adatta al risultato descritto da questo oggetto.
	 */
	public synchronized boolean waitWhileFalse(long msTimeout) throws InterruptedException {
		return waitWhileStateIs(false, msTimeout);
	} // end waitWhileFalse()

	/**
	 * Attende per il tempo di <i>msTimeout</i> se lo stato iniziale 
	 * dell'oggetto e' <i>diverso a <b>True</b></i>.
	 * L'esito � False altrimenti True.
	 * 
	 * @param msTimeout il periodo.
	 * @return un boolean.
	 * @throws InterruptedException Getta un'eccezione adatta al risultato descritto da questo oggetto.
	 */
	public synchronized boolean waitUntilTrue(long msTimeout) throws InterruptedException {
		return waitUntilStateIs(true, msTimeout);
	} // end waitUntilTrue()

	/**
	 * Attende per il tempo di <i>msTimeout</i> se lo stato iniziale 
	 * dell'oggetto e' <i>diverso a <b>False</b></i>.
	 * L'esito � False altrimenti True.
	 *  
	 * @param msTimeout il periodo.
	 * @return un boolean.
	 * @throws InterruptedException Getta un'eccezione adatta al risultato descritto da questo oggetto.
	 */
	public synchronized boolean waitUntilFalse(long msTimeout) throws InterruptedException {
		return waitUntilStateIs(false, msTimeout);
	} // end waitUntilFalse()

	
	/**
	 * Attende per il tempo di <i>msTimeout</i> se lo stato iniziale 
	 * dell'oggetto e' <i>uguale a <b>Stato</b></i>.
	 * Altrimenti confronta le due variabili se sono <i>diverse</i> e ritorna l'esito.
	 * 
	 * @param state
	 * @param msTimeout
	 * @return boolean 
	 * @throws InterruptedException
	 */
	public synchronized boolean waitWhileStateIs(boolean state, long msTimeout) throws InterruptedException {
		if ( msTimeout == 0 ) {
			while ( value == state ) {
				wait();		// wait indefinitely until notified
			}
			// condition has finally been met
			return true;
		}

		// only wait for the specified amount of time
		long endTime = System.currentTimeMillis() + msTimeout;
		long msRemaining = msTimeout;

		while ( (value == state) && (msRemaining > 0) ) {
			wait(msRemaining);
			msRemaining = endTime - System.currentTimeMillis();
		}
		// may have timed out, or may have met value, calculate return value.
		return ( value != state );
	} // end waitWhileStateIs()
	
	/**
	 * Attende per il tempo di <i>msTimeout</i> se lo stato iniziale 
	 * dell'oggetto e' <i>diverso a <b>Stato</b></i>.
	 * Altrimenti confronta le due variabili se sono <i>uguali</i> e ritorna l'esito.
	 * 
	 * @param state
	 * @param msTimeout
	 * @return boolean
	 * @throws InterruptedException
	 */
	public synchronized boolean waitUntilStateIs(boolean state, long msTimeout) throws InterruptedException {
		if ( msTimeout == 0 ) {
			while ( value != state ) {
				wait();		// wait indefinitely until notified
			}
			// condition has finally been met
			return true;
		}

		// only wait for the specified amount of time
		long endTime = System.currentTimeMillis() + msTimeout;
		long msRemaining = msTimeout;

		while ( (value != state) && (msRemaining > 0) ) {
			wait(msRemaining);
			msRemaining = endTime - System.currentTimeMillis();
		}

		// may have timed out, or may have met value, calculate return value.
		return ( value == state );
	} // end waitUntilStateIs()
}
